home *** CD-ROM | disk | FTP | other *** search
/ Just Call Me Internet / Just Call Me Internet.iso / prog / atari / c / nos042_s / rz.c < prev    next >
C/C++ Source or Header  |  1994-09-16  |  35KB  |  1,518 lines

  1. /****************************************************************************
  2. *    Language     :    Turbo C 2.0                                                *
  3. *    Logfile        :    rz.c                                                    *
  4. *    Project        :    Comms library.                                            *
  5. *    Date         :    24 Jan 90                                                *
  6. *    Revision     :    1.1        GT    PC version.                                    *
  7. *    07 Mar 90    :    1.2        GT    Background transfer.                        *
  8. *    25 Oct 92    :    1.3        GT    KA9Q mods.                                    *
  9. *    30 Jan 93    :    1.4        GT    Fix KA9Q background transfer.                *
  10. *    20 Feb 93    :    1.5        GT    Bump HOWMANY to 2048.                        *
  11. *    21 Feb 93    :    1.6        GT    Allocate buffer on heap.                    *
  12. *    08 May 93    :    1.7        GT    Fix warnings.                                *
  13. *****************************************************************************
  14. *    Purpose        :    File receive driver.                                    *
  15. *****************************************************************************
  16. *                :    This module is based on the equivalent module in the    *
  17. *                :    31 Aug 87 version of rz/sz.                                *
  18. *    $Id: rz.c 1.5 93/07/16 11:49:53 ROOT_DOS Exp $
  19. *
  20. *  ATARI Version by David Nash - dnash@chaos.demon.co.uk
  21. *
  22. ****************************************************************************/
  23.  
  24. #include    <io.h>
  25. #include    <fcntl.h>
  26. #include    <stdio.h>
  27. #include    <stdlib.h>
  28. #include    <signal.h>
  29. #include    <setjmp.h>
  30. #include    <ctype.h>
  31. #include    <time.h>
  32. #include    <string.h>
  33. #include    <process.h>
  34. #include    <sys/types.h>
  35. #include    <sys/stat.h>
  36. #include    <dos.h>
  37. #ifdef ATARI
  38. #include <ext.h>
  39. #endif
  40. #include    "zmodem.h"
  41. #include    "sz.h"
  42. #include    "rbsb.h"        /* most of the system dependent stuff here        */
  43. #include    "zm.h"
  44. #include    "global.h"
  45. #ifdef    DEBUGZ
  46. #include    "tty.h"
  47. #endif
  48.  
  49.  
  50. /*
  51.  * Max value for HOWMANY is 255.
  52.  *   A larger value reduces system overhead but may evoke kernel bugs.
  53.  *   133 corresponds to an XMODEM/CRC sector
  54.  */
  55.  
  56. #ifndef HOWMANY
  57. #define HOWMANY 2048            /* was 133                                        */
  58. #endif
  59.  
  60. #undef    RETRYMAX
  61. #define RETRYMAX    5
  62.  
  63. #define UNIXFILE 0x8000        /* the S_IFREG file mask bit for stat            */
  64. #define DEFBYTL 2000000000L    /* default rx file size                            */
  65. #define    CANBREAK
  66.  
  67. static int fout;
  68. static int Eofseen;            /* indicates cpm eof (^Z) has been received        */
  69.  
  70. int Readnum = HOWMANY;         /* Number of bytes to ask for in read () from
  71.                                  modem                                         */
  72.  
  73. static long Bytesleft;        /* number of bytes of incoming file left        */
  74. static long Modtime;        /* Unix style mod time for incoming file        */
  75. static short Filemode;        /* Unix style mode for incoming file            */
  76. static char Pathname[PATHLEN];
  77.  
  78. static int Batch = 0;
  79. static int MakeLCPathname = TRUE; /* make received pathname lower case        */
  80. static int Nflag = 0;        /* Don't really transfer files                    */
  81. static int Rxbinary = FALSE; /* receive all files in bin mode                */
  82. static int Rxascii = FALSE;    /* receive files in ascii (translate) mode        */
  83. static int Thisbinary;        /* current file is to be received in bin mode    */
  84. static int rz_blklen;        /* record length of received packets            */
  85. static char secbuf[KSIZE + 1];
  86. #if    0
  87. static char linbuf[HOWMANY];
  88. #endif
  89. static char *linbuf = 0;    /* -> receive buffer                            */
  90. int Lleft = 0;                /* number of characters in linbuf                */
  91. static int Filcnt = 0;        /* no of files transferred                        */
  92.  
  93. #if    0
  94. time_t timep[2];
  95. #endif
  96. static int nocommand = FALSE; /* TRUE - disallow remote commands            */
  97.  
  98. static int tryzhdrtype = ZRINIT; /* Header type to send corresponding to Last
  99.                                     rx close                                */
  100.  
  101.  
  102. /****************************************************************************
  103. *    Local prototypes.                                                        *
  104. ****************************************************************************/
  105.  
  106. #if    0
  107. static void bibi (int n);
  108. #endif
  109. static void chkinvok (char protocol);
  110. static void purgeline (void);
  111. static void uncaps (char *s);
  112. static int IsAnyLower (char *s);
  113. static void canit (void);
  114. static void report (int sct);
  115. static void checkpath (char *name);
  116. static int tryz (void);
  117. static int rzfiles (void);
  118. static int rzfile (void);
  119. static void zmputs (char *s);
  120. static int closeit (void);
  121. static void ackbibi (void);
  122. static int sys2 (char *s);
  123. static void exec2 (char *s);
  124. static long getfree (void);
  125. static int wcreceive (int argc, char **argp);
  126. static int wcrxpn (char *rpn);
  127. static int wcrx (void);
  128. static int wcgetsec (char *rxbuf, int maxtime);
  129. static int procheader (char *name);
  130. static int putsec (char *buf, int n);
  131.  
  132.                                
  133. /****************************************************************************
  134. *    getfree                                                                    *
  135. *    Routine to calculate the free bytes on the current file system.            *
  136. *    ~0 means many free bytes (unknown).                                        *
  137. ****************************************************************************/
  138.  
  139. static long getfree (void)
  140.     {
  141.     return (~0L);    /* many free bytes ... */
  142.     }    /* static long getfree (void) */
  143.  
  144.  
  145. #if    0
  146. /****************************************************************************
  147. *    bibi                                                                    *
  148. *    Called by signal interrupt or terminate to clean things up.                *
  149. ****************************************************************************/
  150. static void bibi (int n)
  151.     {
  152.     n = n;
  153.     if (_Zmodem)
  154.         {
  155. #ifdef    DEBUGZ
  156.         _tout ("\r\n\nbibi: calling zmputs (_Attn)\r\n");
  157. #endif
  158.         zmputs (_Attn);
  159.         }
  160.     
  161.     canit ();
  162.     _zperr_ ("Interrupted\n");
  163.     closeit ();
  164. #ifdef    DEBUGZ
  165.     _tout ("bibi: doing longjmp (_tohere, -1)\r\n");
  166. #endif
  167.     longjmp (_tohere, -1);
  168.     }    /* static void bibi (int n) */
  169. #endif
  170.  
  171.  
  172. /****************************************************************************
  173. *    _getfile                                                                *
  174. *    Receives file(s).  Returns 0 if successful.                                *
  175. ****************************************************************************/
  176.  
  177. int _getfile (int s, char protocol, char *options, char *filename,
  178.               void (*reporter) (int type, void *data))
  179.     {
  180.     char *cp;
  181.     int npats;
  182.     char **patts;
  183.     int exitcode = 0;
  184. #if    0
  185.     void (*sigint_sav) (int);
  186.     void (*sigterm_sav) (int);
  187. #endif
  188.  
  189.     /* Initialise global variables. */
  190.  
  191.     _z_socket = s;
  192.     Batch = 0;
  193.     _do_report = _zperr;
  194.     Filcnt = 0;
  195.     Lleft = 0;
  196.     MakeLCPathname = TRUE;
  197.     Nflag = 0;
  198.     nocommand = FALSE;
  199.     _Nozmodem = 0;
  200.     _Quiet = 0;
  201.     Readnum = HOWMANY;
  202.     Rxascii = FALSE;
  203.     Rxbinary = FALSE;
  204.     _Rxtimeout = 100;
  205.     _sending = FALSE;
  206.     tryzhdrtype = ZRINIT;
  207.     _Verbose = 0;
  208.     _Wcsmask = 0377;
  209.     _Zmodem = 0;
  210.     _Zrwindow = 1400;
  211.  
  212.     chkinvok (protocol);                    /* choose protocol                */
  213.     npats = 0;
  214.  
  215.     /* Parse options. */
  216.  
  217.     cp = options;
  218.     while (*cp != '\0')
  219.         {
  220.         switch (*cp++)
  221.             {
  222.             case '7':                        /* strip top bit                */
  223.                 _Wcsmask = 0177;
  224.  
  225.             case 'a':                        /* ASCII transfer                */
  226.                 Rxascii = TRUE;
  227.                 break;
  228.  
  229.             case 'b':                        /* binary transfer                */
  230.                 Rxbinary = TRUE;
  231.                 break;
  232.  
  233.             case 'c':                        /* XMODEM/CRC                    */
  234.                 _Crcflg = TRUE;
  235.                 break;
  236.  
  237.             case 'D':                        /* fake file transfer            */
  238.                 Nflag = TRUE;
  239.                 break;
  240.  
  241.             case 'i':                        /* disallow remote command        */
  242.                 nocommand = TRUE;
  243.                 break;
  244.                 
  245.             case 'e':                        /* escape ctl chars                */
  246.                 _Zctlesc = 1;
  247.                 break;
  248.  
  249.             case 'p':                        /* 'protect' option                */
  250.                 _Lzmanag = ZMPROT;
  251.                 break;
  252.  
  253.             case 'q':                        /* quiet                        */
  254.                 _Quiet = TRUE;
  255.                 _Verbose = 0;
  256.                 break;
  257.  
  258.             case 't':                        /* change timeout                */
  259.                 sscanf (cp, "%d", &_Rxtimeout);
  260.                 if (_Rxtimeout < 10 || _Rxtimeout > 1000)
  261.                     return (ERROR);
  262.  
  263.                 cp = _stbnb (cp);
  264.                 break;
  265.  
  266.             case 'w':                        /* window size                    */
  267.                 sscanf (cp, "%d", &_Zrwindow);
  268.                 cp = _stbnb (cp);
  269.                 break;
  270.  
  271.             case 'u':                        /* no lower case convert        */
  272.                 MakeLCPathname = FALSE;
  273.                 break;
  274.                 
  275.             case 'v':                        /* debug info                    */
  276.                 ++_Verbose;
  277.                 break;
  278.  
  279.             default:
  280.                 return (ERROR);
  281.             }    /* switch (*cp++) */
  282.             
  283.         }    /* while (*cp != '\0') */
  284.  
  285.     /* Get filename. */
  286.     
  287.     if (filename != NULL)
  288.         {
  289.         npats = 1;
  290.         patts = &filename;
  291.         }
  292.  
  293.     if (npats > 1)
  294.         return (ERROR);
  295.         
  296.     if (Batch && npats)
  297.         return (ERROR);
  298.  
  299.     /* Get reporter function */
  300.  
  301.     if (reporter != NULL)
  302.         _do_report = reporter;                /* user supplied fn                */
  303.  
  304. #if    0
  305.     if (_Verbose)
  306.         {
  307.         if ((_zperr_handle = open (LOGFILE,
  308.                                    O_CREAT | O_APPEND | O_WRONLY | O_TEXT,
  309.                                    S_IFREG | S_IWRITE)) == -1)
  310.             {
  311.             char buff[80];
  312.             
  313.             sprintf (buff, "Can't open log file %s: %s\n",
  314.                      LOGFILE, strerror (errno));
  315.             (*_do_report) (2, buff);
  316.             (*_do_report) (3, &Filcnt);        /* report no of files            */
  317.             return (ERROR);
  318.             }
  319.             
  320.         _do_report = _zperr;                /* use default reporter            */
  321.         }
  322. #endif
  323.  
  324.     if (!_Quiet)
  325.         {
  326.         if (_Verbose == 0)
  327.             _Verbose = 2;
  328.  
  329.         }
  330.  
  331. #if    0
  332.     if ((sigint_sav = signal (SIGINT, bibi)) == SIG_IGN)
  333.         signal (SIGINT, SIG_IGN);
  334.     else
  335.         signal (SIGINT, bibi);
  336.  
  337. #endif
  338.  
  339. #if    0
  340.     sigint_sav = signal (SIGINT, bibi);
  341.     sigterm_sav = signal (SIGTERM, bibi);
  342. #endif
  343.         
  344.     /* Set up escape routes. */
  345.  
  346.     if (setjmp (_tohere) != 0)
  347.         {
  348. #ifdef    DEBUGZ
  349.         _tout ("getfile: exiting via _tohere jump\r\n");
  350. #endif
  351.         (*_do_report) (3, &Filcnt);            /* report files transferred        */
  352. #if    0
  353.         signal (SIGINT, sigint_sav);
  354.         signal (SIGTERM, sigterm_sav);
  355.         (void) close (_zperr_handle);
  356. #endif
  357.         return (-2);                        /* user abort                    */
  358.         }
  359.  
  360.     if (setjmp (_nocarrier) != 0)
  361.         {
  362. #ifdef    DEBUGZ
  363.         _tout ("getfile: exiting via _nocarrier jump\r\n");
  364. #endif
  365.         (*_do_report) (3, &Filcnt);            /* report files transferred        */
  366. #if    0
  367.         signal (SIGINT, sigint_sav);
  368.         signal (SIGTERM, sigterm_sav);
  369.         (void) close (_zperr_handle);
  370. #endif
  371.         return (-3);                        /* lost carrier                    */
  372.         }
  373.  
  374.     /* Get the file(s). */
  375.     
  376.     if (wcreceive (npats, patts) == ERROR)
  377.         {
  378.         exitcode = 0200;
  379.         canit ();
  380.         }
  381.         
  382.     if (exitcode && !_Zmodem)            /* Bellow again with all thy might. */
  383.         canit ();
  384.         
  385.     if (!_Quiet)
  386.         _say ("\n");
  387.  
  388.     (*_do_report) (3, &Filcnt);            /* report files transferred            */
  389. #if    0
  390.     signal (SIGINT, sigint_sav);
  391.     signal (SIGTERM, sigterm_sav);
  392.     (void) close (_zperr_handle);
  393. #endif
  394.     return (exitcode);
  395.     }    /* int _getfile (int s, char protocol, char *options, char *filename,
  396.              void (*reporter) (int type, void *data)) */
  397.              
  398.  
  399. /****************************************************************************
  400. *    wcreceive                                                                *
  401. *    Let's receive something already.                                        *
  402. ****************************************************************************/
  403.  
  404. #if 0
  405. static char *rbmsg = "Ready to receive.\n"
  406.                      "To begin transfer, issue the send command "
  407.                      "to your modem program\r\n";
  408. #endif
  409.  
  410. static int wcreceive (int argc, char **argp)
  411.     {
  412.     int c;
  413.  
  414.     if (Batch || argc == 0)
  415.         {
  416.         /* ZMODEM / YMODEM BATCH */
  417.         
  418.         _Crcflg = (_Wcsmask == 0377);
  419. #if 0
  420.         if (!_Quiet)
  421.             _say (rbmsg);
  422.  
  423. #endif
  424.         
  425.         if ((c = tryz ()) != 0)
  426.             {
  427.             if (c == ZCOMPL)
  428.                 return OK;
  429.                 
  430.             if (c == ERROR)
  431.                 goto fubar;
  432.                 
  433.             c = rzfiles ();
  434.             if (c)
  435.                 goto fubar;
  436.                 
  437.             }    /* if ((c = tryz ()) != 0) */
  438.         else
  439.             {
  440.             for (;;)
  441.                 {
  442.                 if (wcrxpn (secbuf) == ERROR)
  443.                     goto fubar;
  444.                     
  445.                 if (secbuf[0] == 0)
  446.                     return OK;
  447.                     
  448.                 if (procheader (secbuf) == ERROR)
  449.                     goto fubar;
  450.                     
  451.                 if (wcrx () == ERROR)
  452.                     goto fubar;
  453.                     
  454.                 }    /* for (;;) */
  455.                 
  456.             }    /* else */
  457.             
  458.         }    /* if (Batch || argc == 0) */
  459.     else
  460.         {
  461.         /* XMODEM */
  462.         
  463.         Bytesleft = DEFBYTL;
  464.         Filemode = 0;
  465.         Modtime = 0L;
  466.  
  467.         procheader ("");
  468.         strcpy (Pathname, *argp);
  469.         checkpath (Pathname);
  470.         (*_do_report) (0, Pathname);
  471.         _say ("\nReady to receive %s\r\n", Pathname);
  472.         if ((fout = open (Pathname,
  473.                           O_CREAT | O_TRUNC | O_WRONLY | O_BINARY,
  474.                           S_IFREG | S_IWRITE)) == -1)
  475.             return ERROR;
  476.             
  477.         if (wcrx () == ERROR)
  478.             goto fubar;
  479.  
  480.         ++Filcnt;
  481.         }    /* else */
  482.         
  483.     return OK;
  484.  
  485.     /* Transfer failed - clean up. */
  486.     
  487. fubar:
  488.     canit ();
  489.     if (fout != -1)
  490.         close (fout);
  491.  
  492.     return ERROR;
  493.     }    /* static int wcreceive (int argc, char **argp) */
  494.     
  495.  
  496. /****************************************************************************
  497. *    wcrxpn                                                                    *
  498. *    Fetch a pathname from the other end as a C ctyle ASCIZ string.  Length    *
  499. *    is indeterminate as long as less than rz_blklen.  A null string         *
  500. *    represents no more files (YMODEM).                                        *
  501. ****************************************************************************/
  502.  
  503. static int wcrxpn (char *rpn)
  504.     {
  505.     int c;
  506.  
  507.     purgeline ();
  508.  
  509. et_tu:
  510.     _firstsec = TRUE;
  511.     Eofseen = FALSE;
  512.     _sendline (_Crcflg ? WANTCRC : NAK);
  513.     Lleft = 0;                            /* Do read next time ...             */
  514.     while ((c = wcgetsec (rpn, 100)) != 0)
  515.         {
  516.         if (c == WCEOT)
  517.             {
  518.             _zperr_ ("Pathname fetch returned %d", c);
  519.             _sendline (ACK);
  520.             Lleft = 0;                    /* Do read next time ...             */
  521.             _readline (1);
  522.             goto et_tu;
  523.             }
  524.  
  525.         return ERROR;
  526.         }    /* while ((c = wcgetsec (rpn, 100)) != 0) */
  527.         
  528.     _sendline (ACK);
  529.     return OK;
  530.     }    /* static int wcrxpn (char *rpn) */
  531.  
  532.  
  533. /****************************************************************************
  534. *    wcrx                                                                    *
  535. *    Adapted from CMODEM13.C, written by Jack M Wierda and Roderick W Hart.    *
  536. ****************************************************************************/
  537.  
  538. static int wcrx (void)
  539.     {
  540.     int sectnum, sectcurr;
  541.     char sendchar;
  542.     int cblklen;                        /* bytes to dump this block            */
  543.  
  544.     _firstsec = TRUE;
  545.     sectnum = 0;
  546.     Eofseen = FALSE;
  547.     sendchar = (char) (_Crcflg ? WANTCRC : NAK);
  548.  
  549.     for (;;)
  550.         {
  551.         _sendline (sendchar);            /* send it now, we're ready!        */
  552.         Lleft = 0;                        /* Do read next time ...            */
  553.         sectcurr = wcgetsec (secbuf, (sectnum & 0177) ? 50 : 130);
  554.         report (sectcurr);
  555.         if (sectcurr == (sectnum + 1 & _Wcsmask))
  556.             {
  557.             sectnum++;
  558.             cblklen = Bytesleft > rz_blklen ? rz_blklen : (int) Bytesleft;
  559.             if (putsec (secbuf, cblklen) == ERROR)
  560.                 return ERROR;
  561.  
  562.             if ((Bytesleft -= cblklen) < 0)
  563.                 Bytesleft = 0;
  564.  
  565.             sendchar = ACK;
  566.             }
  567.         else if (sectcurr == (sectnum & _Wcsmask))
  568.             {
  569.             _zperr_ ("Received dup Sector");
  570.             sendchar = ACK;
  571.             }
  572.         else if (sectcurr == WCEOT)
  573.             {
  574.             if (closeit ())
  575.                 return ERROR;
  576.  
  577.             _sendline (ACK);
  578.             Lleft = 0;                    /* Do read next time ...            */
  579.             return OK;
  580.             }
  581.         else if (sectcurr == ERROR)
  582.             return ERROR;
  583.         else
  584.             {
  585.             _zperr_ ("Sync Error");
  586.             return ERROR;
  587.             }
  588.  
  589.         }    /* for (;;) */
  590.         
  591.     }    /* static int wcrx (void) */
  592.     
  593.  
  594. /****************************************************************************
  595. *    wcgetsec                                                                *
  596. *    Fetches a Ward Christensen type sector.  Returns sector number             *
  597. *    encountered or ERROR if valid sector not received, or CAN CAN received    *
  598. *    or WCEOT if eot sector.  <maxtime> is timeout for first char, set to 4    *
  599. *    seconds thereafter.  NO ACK IS SENT IF SECTOR IS RECEIVED OK (Caller    *
  600. *    must do that when he is good and ready to get next sector).                *
  601. ****************************************************************************/
  602.  
  603. static int wcgetsec (char *rxbuf, int maxtime)
  604.     {
  605.     int checksum, wcj, firstch;
  606.     unsigned short oldcrc;
  607.     char *p;
  608.     int sectcurr;
  609.  
  610.     for (_Lastrx = _errors = 0; _errors < RETRYMAX; _errors++)
  611.         {
  612.         if ((firstch = _readline (maxtime)) == STX)
  613.             {
  614.             rz_blklen = KSIZE;
  615.             goto get2;
  616.             }
  617.  
  618.         if (firstch == SOH)
  619.             {
  620.             rz_blklen = SECSIZ;
  621.  
  622. get2:
  623.             sectcurr = _readline (1);
  624.             if ((sectcurr + (oldcrc = _readline (1))) == _Wcsmask)
  625.                 {
  626.                 oldcrc = checksum = 0;
  627.                 for (p = rxbuf, wcj = rz_blklen; --wcj >= 0;)
  628.                     {
  629.                     if ((firstch = _readline (1)) < 0)
  630.                         goto bilge;
  631.                         
  632.                     oldcrc = updcrc (firstch, oldcrc);
  633.                     checksum += (*p++ = (char) firstch);
  634.                     }
  635.                     
  636.                 if ((firstch = _readline (1)) < 0)
  637.                     goto bilge;
  638.                     
  639.                 if (_Crcflg)
  640.                     {
  641.                     oldcrc = updcrc (firstch, oldcrc);
  642.                     if ((firstch = _readline (1)) < 0)
  643.                         goto bilge;
  644.                         
  645.                     oldcrc = updcrc (firstch, oldcrc);
  646.                     if (oldcrc & 0xFFFF)
  647.                         _zperr_ ( "CRC");
  648.                     else
  649.                         {
  650.                         _firstsec = FALSE;
  651.                         return sectcurr;
  652.                         }
  653.  
  654.                     }    /* if (_Crcflg) */
  655.                 else if (((checksum - firstch) & _Wcsmask) == 0)
  656.                     {
  657.                     _firstsec = FALSE;
  658.                     return sectcurr;
  659.                     }
  660.                 else
  661.                     _zperr_ ( "Checksum");
  662.  
  663.                 }    /* if ((sectcurr + (oldcrc = _readline (1))) == _Wcsmask) */
  664.             else
  665.                 _zperr_ ("Sector number garbled");
  666.  
  667.             }    /* if (firstch == SOH) */
  668.         else if (firstch == EOT && Lleft == 0)    /* make sure eot really is
  669.                                                    eot and not just mixmash    */
  670.             return WCEOT;
  671.         else if (firstch == CAN)
  672.             {
  673.             if (_Lastrx == CAN)
  674.                 {
  675.                 _zperr_ ("Sender CANcelled");
  676.                 return ERROR;
  677.                 }
  678.             else
  679.                 {
  680.                 _Lastrx = CAN;
  681.                 continue;
  682.                 }
  683.  
  684.             }    /* else if (firstch == CAN) */
  685.         else if (firstch == ZTIMEOUT)
  686.             {
  687.             if (_firstsec)
  688.                 goto humbug;
  689.  
  690. bilge:
  691.             _zperr_ ( "TIMEOUT");
  692.             }
  693.         else
  694.             _zperr_ ( "Got 0%o sector header", firstch);
  695.  
  696. humbug:
  697.         _Lastrx = 0;
  698.         while (_readline (1) != ZTIMEOUT)
  699.             ;
  700.  
  701.         if (_firstsec)
  702.             {
  703.             _sendline (_Crcflg ? WANTCRC : NAK);
  704.             Lleft = 0;                    /* Do read next time ...            */
  705.             }
  706.         else
  707.             {
  708.             maxtime = 40;
  709.             _sendline (NAK);
  710.             Lleft = 0;                    /* Do read next time ...            */
  711.             }
  712.  
  713.         }    /* for (_Lastrx = _errors = 0; _errors < RETRYMAX; _errors++) */
  714.         
  715.     /* try to stop the bubble machine. */
  716.     
  717.     canit ();
  718.     return ERROR;
  719.     }    /* static int wcgetsec (char *rxbuf, int maxtime) */
  720.     
  721.  
  722. /****************************************************************************
  723. *    _readline                                                                *
  724. *    This version of _readline is reasonably well suited for reading many     *
  725. *    characters (except, currently, for the Regulus version!).  Timeout is    *
  726. *    in tenths of seconds.                                                    *
  727. ****************************************************************************/
  728.  
  729. int _readline (int timeout)
  730.     {
  731.     int n;
  732.     static char *cdq;            /* pointer for removing chars from linbuf    */
  733.     time_t start;                        /* start for timeout                */
  734.  
  735.     if (linbuf == 0)
  736.         linbuf = mallocw (HOWMANY);
  737.         
  738.     if (--Lleft >= 0)
  739.         {
  740.         if (_Verbose > 8)
  741.             {
  742.             _say ("%02x ", *cdq & 0377);
  743.             }
  744.  
  745.         return (*cdq++ & _Wcsmask);
  746.         }
  747.  
  748.     n = timeout / 10;
  749.     if (n < 2)
  750.         n = 3;        
  751.  
  752.     time (&start);
  753.     if (_Verbose > 5)
  754.         _vfile ("Calling read: alarm=%d  Readnum=%d ", n, Readnum);
  755.         
  756.     _no_carrier ();
  757.     while (1)
  758.         {
  759.         Lleft = _receive ((unsigned char *) (cdq = linbuf), Readnum);
  760.         if (Lleft != 0)
  761.             break;                        /* got something                    */
  762.  
  763.         if (time (NULL) >= start + n)
  764.             {
  765.             _zperr_ ("ZTIMEOUT");
  766.             return (ZTIMEOUT);
  767.             }
  768.  
  769.         }
  770.         
  771.     if (_Verbose > 5)
  772.         {
  773.         _say ("Read returned %d bytes\n", Lleft);
  774.         }
  775.  
  776.     if (Lleft < 1)
  777.         return ZTIMEOUT;
  778.  
  779.     --Lleft;
  780.     if (_Verbose > 8)
  781.         {
  782.         _say ("%02x ", *cdq & 0377);
  783.         }
  784.  
  785.     return (*cdq++ & _Wcsmask);
  786.     }    /* int _readline (int timeout) */
  787.  
  788.  
  789. /****************************************************************************
  790. *    purgeline                                                                *
  791. *    Purge the modem input queue of all characters.                            *
  792. ****************************************************************************/
  793.  
  794. static void purgeline (void)
  795.     {
  796.     unsigned char c;
  797.     
  798.     Lleft = 0;
  799.     while (_rdchk () > 0)
  800.         _receive (&c, 1);
  801.         
  802.     }    /* static void purgeline (void) */
  803.  
  804.  
  805. /****************************************************************************
  806. *    procheader                                                                *
  807. *    Process incoming file information header.                                *
  808. ****************************************************************************/
  809.  
  810. static int procheader (char *name)
  811.     {
  812.     int openmode;
  813.     char *p;
  814.  
  815.     /* set default parameters and overrides */
  816.  
  817.     (*_do_report) (0, name);
  818.     openmode = O_CREAT | O_TRUNC | O_WRONLY | O_BINARY;
  819.     Thisbinary = (!Rxascii) || Rxbinary;
  820.     if (_Lzmanag)
  821.         _zmanag = _Lzmanag;
  822.  
  823.     /* Process ZMODEM remote file management requests. */
  824.     
  825.     if (!Rxbinary && _zconv == ZCNL)    /* Remote ASCII override             */
  826.         Thisbinary = 0;
  827.         
  828.     if (_zconv == ZCBIN)                /* Remote Binary override             */
  829.         Thisbinary = TRUE;
  830.     else if (_zmanag == ZMAPND)
  831.         openmode = O_APPEND | O_WRONLY | O_BINARY;
  832.  
  833.     /* ZMPROT check for existing file */
  834.     
  835.     if (_zmanag == ZMPROT && (fout = open (name, O_RDONLY, S_IREAD)) != -1)
  836.         {
  837.         close (fout);
  838.         return ERROR;
  839.         }
  840.  
  841.     Bytesleft = DEFBYTL;
  842.     Filemode = 0;
  843.     Modtime = 0L;
  844.  
  845.     p = name + 1 + strlen (name);
  846.     if (*p)
  847.         {
  848.         /* file coming from Unix or DOS system */
  849.  
  850.         sscanf (p, "%ld%lo%o", &Bytesleft, &Modtime, &Filemode);
  851.         if (Filemode & UNIXFILE)
  852.             ++Thisbinary;
  853.  
  854.         if (_Verbose)
  855.             {
  856.             _say ("Incoming: %s %ld %lo %o\n",
  857.                   name, Bytesleft, Modtime, Filemode);
  858.             }
  859.             
  860.         }    /* if (*p) */
  861.     else
  862.         {
  863.         /* File coming from CP/M system */
  864.         
  865.         for (p = name; *p; ++p)            /* change / to _                     */
  866.             if ( *p == '/')
  867.                 *p = '_';
  868.                 
  869.         if ( *--p == '.')                /* zap trailing period                 */
  870.             *p = 0;
  871.             
  872.         }    /* else */
  873.  
  874.     if (!_Zmodem && MakeLCPathname && !IsAnyLower (name))
  875.         uncaps (name);
  876.         
  877.     strcpy (Pathname, name);
  878.     if (_Verbose)
  879.         {
  880.         _say ("Receiving %s %s\n",
  881.               name, Thisbinary ? "BIN" : "ASCII");
  882.         }
  883.         
  884.     checkpath (name);
  885.     if (Nflag)
  886.         name = "nul";                    /* send to bit bucket                */
  887.  
  888.     if ((fout = open (name, openmode, S_IFREG | S_IWRITE)) == -1)
  889.         {
  890.         _vfile ("Can't open %s mode %x, %s\n",
  891.                 name, openmode, strerror (errno));
  892.         return ERROR;
  893.         }
  894.         
  895.     return OK;
  896.     }    /* static int procheader (char *name) */
  897.     
  898.  
  899. /****************************************************************************
  900. *    putsec                                                                    *
  901. *    Writes the <n> characters of <buf> to receive file fout.  If not in     *
  902. *    binary mode, carriage returns, and all characters starting with CPMEOF     *
  903. *    are discarded.                                                            *
  904. ****************************************************************************/
  905.  
  906. static int putsec (char *buf, int n)
  907.     {
  908.     char *p, *q;
  909.     char locbuf[KSIZE + 1];
  910.     int qcount;                            /* no of chars in local buffer        */
  911.     
  912.     if (Thisbinary)
  913.         {
  914.         write (fout, buf, n);
  915. #if    0
  916.         for (p = buf; --n >= 0;)
  917.             putc (*p++, fout);
  918.  
  919. #endif        
  920.         }
  921.     else
  922.         {
  923.         if (Eofseen)
  924.             return OK;
  925.  
  926.         q = locbuf;
  927.         qcount = 0;
  928.         for (p = buf; --n >= 0; ++p)
  929.             {
  930. #if    0
  931.             /* We'll keep CR under MesS-DOS. */
  932.             
  933.             if (*p == '\r')
  934.                 continue;
  935.  
  936. #endif
  937.             if (*p == CPMEOF)
  938.                 {
  939.                 Eofseen = TRUE;
  940.                 return OK;
  941.                 }
  942.  
  943.             *q++ = *p;                    /* put byte in write buffer            */
  944.             qcount++;
  945. #if    0
  946.             putc (*p ,fout);
  947. #endif
  948.             }    /* for (p = buf; --n >= 0; ++p) */
  949.  
  950.         if (qcount != 0)
  951.             write (fout, locbuf, qcount);
  952.             
  953.         }    /* else */
  954.         
  955.     return OK;
  956.     }    /* static int putsec (char *buf, int n) */
  957.     
  958.  
  959. /****************************************************************************
  960. *    uncaps                                                                    *
  961. *    Make string <s> lower case.                                                *
  962. ****************************************************************************/
  963.  
  964. static void uncaps (char *s)
  965.     {
  966.     for (; *s; ++s)
  967.         if (isupper (*s))
  968.             *s = tolower (*s);
  969.             
  970.     }    /* static void uncaps (char *s) */
  971.  
  972.  
  973. /****************************************************************************
  974. *    IsAnyLower                                                                *
  975. *    IsAnyLower returns TRUE if string s has lower case letters.                *
  976. ****************************************************************************/
  977.  
  978. static int IsAnyLower (char *s)
  979.     {
  980.     for (; *s; ++s)
  981.         if (islower (*s))
  982.             return TRUE;
  983.             
  984.     return FALSE;
  985.     }    /* static int IsAnyLower (char *s) */
  986.  
  987.  
  988. /****************************************************************************
  989. *    canit                                                                    *
  990. *    Send cancel string to get the other end to shut up.                        *
  991. ****************************************************************************/
  992.  
  993. static void canit (void)
  994.     {
  995. #ifdef    DEBUGZ
  996.     _tout ("canit: calling _canit ()\r\n");
  997. #endif
  998.     _canit ();
  999.     Lleft = 0;                            /* Do read next time ...             */
  1000. #ifdef    DEBUGZ
  1001.     _tout ("leaving canit ()\r\n");
  1002. #endif
  1003.     }    /* static void canit (void) */
  1004.  
  1005.  
  1006. /****************************************************************************
  1007. *    report                                                                    *
  1008. *    Print <sct>.                                                            *
  1009. ****************************************************************************/
  1010.  
  1011. static void report (int sct)
  1012.     {
  1013.     if (_Verbose > 1)
  1014.         _say ("%03d%c", sct, sct % 10 ? ' ' : '\r');
  1015.         
  1016.     }    /* static void report (int sct) */
  1017.  
  1018.  
  1019. /****************************************************************************
  1020. *    chkinvok                                                                *
  1021. *    Set chosen protocol.                                                    *
  1022. ****************************************************************************/
  1023.  
  1024. static void chkinvok (char protocol)
  1025.     {
  1026.     if (protocol == 'z')
  1027.         Batch = TRUE;
  1028.         
  1029.     if (protocol == 'y')
  1030.         Batch = _Nozmodem = TRUE;
  1031.         
  1032.     }    /* static void chkinvok (char protocol) */
  1033.     
  1034.  
  1035. /****************************************************************************
  1036. *    checkpath                                                                *
  1037. *    Totalitarian Communist pathname processing.                                *
  1038. ****************************************************************************/
  1039.  
  1040. static void checkpath (char *name)
  1041.     {
  1042.     /* No restrictions in this version. */
  1043.  
  1044.     name = name;                        /* silence compiler                    */
  1045.     }    /* static void checkpath (char *name) */
  1046.  
  1047.  
  1048. /****************************************************************************
  1049. *    tryz                                                                    *
  1050. *    Initialize for Zmodem receive attempt, try to activate Zmodem sender.    *
  1051. *    Handles ZSINIT frame.  Return ZFILE if Zmodem filename received, -1 on    *
  1052. *    error, ZCOMPL if transaction finished, else 0.                            *
  1053. ****************************************************************************/
  1054.  
  1055. static int tryz (void)
  1056.     {
  1057.     int c, n;
  1058.     int cmdzack1flg;
  1059.  
  1060.     if (_Nozmodem)                        /* Check for "rb" program name         */
  1061.         return 0;
  1062.         
  1063.     for (n = _Zmodem ? 15 : 5; --n >= 0;)
  1064.         {
  1065.         /* Set buffer length (0) and capability flags. */
  1066.         
  1067.         _stohdr (0L);
  1068. #ifdef CANBREAK
  1069.         _Txhdr[ZF0] = CANFC32 | CANFDX | CANOVIO | CANBRK;
  1070. #else
  1071.         _Txhdr[ZF0] = CANFC32 | CANFDX | CANOVIO;
  1072. #endif
  1073.         if (_Zctlesc)
  1074.             _Txhdr[ZF0] |= TESCCTL;
  1075.             
  1076.         _zshhdr (tryzhdrtype, _Txhdr);
  1077.         if (tryzhdrtype == ZSKIP)        /* Don't skip too far                 */
  1078.             tryzhdrtype = ZRINIT;        /* CAF 8-21-87                         */
  1079.             
  1080. again:
  1081.         switch (_zgethdr (_Rxhdr, 0))
  1082.             {
  1083.             case ZRQINIT:
  1084.                 continue;
  1085.  
  1086.             case ZEOF:
  1087.                 continue;
  1088.  
  1089.             case ZTIMEOUT:
  1090.                 continue;
  1091.  
  1092.             case ZFILE:
  1093.                 _zconv = _Rxhdr[ZF0];
  1094.                 _zmanag = _Rxhdr[ZF1];
  1095.                 _ztrans = _Rxhdr[ZF2];
  1096.                 tryzhdrtype = ZRINIT;
  1097.                 c = _zrdata (secbuf, KSIZE);
  1098.                 if (c == GOTCRCW)
  1099.                     return ZFILE;
  1100.  
  1101.                 _zshhdr (ZNAK, _Txhdr);
  1102.                 goto again;
  1103.  
  1104.             case ZSINIT:
  1105.                 _Zctlesc = TESCCTL & _Rxhdr[ZF0];
  1106.                 if (_zrdata (_Attn, ZATTNLEN) == GOTCRCW)
  1107.                     {
  1108.                     _zshhdr (ZACK, _Txhdr);
  1109.                     goto again;
  1110.                     }
  1111.  
  1112.                 _zshhdr (ZNAK, _Txhdr);
  1113.                 goto again;
  1114.  
  1115.             case ZFREECNT:
  1116.                 _stohdr (getfree ());
  1117.                 _zshhdr (ZACK, _Txhdr);
  1118.                 goto again;
  1119.  
  1120.             case ZCOMMAND:
  1121.                 cmdzack1flg = _Rxhdr[ZF0];
  1122.                 if (_zrdata (secbuf, KSIZE) == GOTCRCW)
  1123.                     {
  1124.                     if (cmdzack1flg & ZCACK1)
  1125.                         _stohdr (0L);
  1126.                     else
  1127.                         {
  1128.                         if (nocommand)
  1129.                             _stohdr (0L);    /* fake command ok                */
  1130.                         else
  1131.                             _stohdr ((long) sys2 (secbuf));
  1132.  
  1133.                         }
  1134.  
  1135.                     purgeline ();        /* dump impatient questions         */
  1136.                     do
  1137.                         {
  1138.                         _zshhdr (ZCOMPL, _Txhdr);
  1139.                         } while (++_errors < 20 && _zgethdr (_Rxhdr,1) != ZFIN);
  1140.                         
  1141.                     ackbibi ();
  1142.                     if (cmdzack1flg & ZCACK1)
  1143.                         if (nocommand)
  1144.                             longjmp (_tohere, -1);    /* don't do it            */
  1145.                         else
  1146.                             exec2 (secbuf);
  1147.  
  1148.                     return ZCOMPL;
  1149.                     }    /* if (_zrdata (secbuf, KSIZE) == GOTCRCW) */
  1150.                     
  1151.                 _zshhdr (ZNAK, _Txhdr);
  1152.                 goto again;
  1153.                 
  1154.             case ZCOMPL:
  1155.                 goto again;
  1156.  
  1157.             default:
  1158.                 continue;
  1159.  
  1160.             case ZFIN:
  1161.                 ackbibi ();
  1162.                 return ZCOMPL;
  1163.  
  1164.             case ZCAN:
  1165.                 return ERROR;
  1166.             }    /* switch (_zgethdr (_Rxhdr, 0)) */
  1167.             
  1168.         }    /* for (n = _Zmodem ? 15 : 5; --n >= 0;) */
  1169.         
  1170.     return 0;
  1171.     }    /* static int tryz (void) */
  1172.     
  1173.  
  1174. /****************************************************************************
  1175. *    rzfiles                                                                    *
  1176. *    Receive one or more files with the ZMODEM protocol.                        *
  1177. ****************************************************************************/
  1178.  
  1179. static int rzfiles (void)
  1180.     {
  1181.     int c;
  1182.  
  1183.     for (;;)
  1184.         {
  1185.         switch (c = rzfile ())
  1186.             {
  1187.             case ZEOF:
  1188.             case ZSKIP:
  1189.                 switch (tryz ())
  1190.                     {
  1191.                     case ZCOMPL:
  1192.                         return OK;
  1193.                         
  1194.                     default:
  1195.                         return ERROR;
  1196.  
  1197.                     case ZFILE:
  1198.                         break;
  1199.                     }
  1200.     
  1201.                 continue;
  1202.  
  1203.             default:
  1204.                 return c;
  1205.  
  1206.             case ERROR:
  1207.                 return ERROR;
  1208.             }    /* switch (c = rzfile ()) */
  1209.             
  1210.         }    /* for (;;) */
  1211.         
  1212.     }    /* static int rzfiles (void) */
  1213.     
  1214.  
  1215. /****************************************************************************
  1216. *    rzfile                                                                    *
  1217. *    Receive a file with ZMODEM protocol.  Assumes file name frame is in     *
  1218. *    secbuf.                                                                    *
  1219. ****************************************************************************/
  1220.  
  1221. static int rzfile (void)
  1222.     {
  1223.     int c, n;
  1224.     long rxbytes;
  1225.     int sent_zm = FALSE;                /* TRUE - sent ZMODEM string        */
  1226.     Eofseen = FALSE;
  1227.     if (procheader (secbuf) == ERROR)
  1228.         {
  1229.         return (tryzhdrtype = ZSKIP);
  1230.         }
  1231.         
  1232.     n = 20;
  1233.     rxbytes = 0l;
  1234.  
  1235.     for (;;)
  1236.         {
  1237.         _stohdr (rxbytes);
  1238.         _zshhdr (ZRPOS, _Txhdr);
  1239.  
  1240. nxthdr:
  1241.         switch (c = _zgethdr (_Rxhdr, 0))
  1242.             {
  1243.             default:
  1244.                 _vfile ("rzfile: _zgethdr returned %d", c);
  1245.                 return ERROR;
  1246.  
  1247.             case ZNAK:
  1248.             case ZTIMEOUT:
  1249.                 if ( --n < 0)
  1250.                     {
  1251.                     _vfile ("rzfile: _zgethdr returned %d", c);
  1252.                     return ERROR;
  1253.                     }
  1254.  
  1255.             case ZFILE:
  1256.                 _zrdata (secbuf, KSIZE);
  1257.                 continue;
  1258.  
  1259.             case ZEOF:
  1260.                 if (_rclhdr (_Rxhdr) != rxbytes)
  1261.                     {
  1262.                     /*
  1263.                      * Ignore eof if it's at wrong place - force
  1264.                      *  a timeout because the eof might have gone
  1265.                      *  out before we sent our zrpos.
  1266.                      */
  1267.  
  1268.                     _errors = 0;
  1269.                     goto nxthdr;
  1270.                     }
  1271.                     
  1272.                 if (closeit ())
  1273.                     {
  1274.                     tryzhdrtype = ZFERR;
  1275.                     _vfile ("rzfile: closeit returned <> 0");
  1276.                     return ERROR;
  1277.                     }
  1278.  
  1279.                 _vfile ("rzfile: normal EOF");
  1280.                 ++Filcnt;
  1281.                 return c;
  1282.  
  1283.             case ERROR:                    /* Too much garbage in header search
  1284.                                            error                             */
  1285.                 if (--n < 0)
  1286.                     {
  1287.                     _vfile ("rzfile: _zgethdr returned %d", c);
  1288.                     return ERROR;
  1289.                     }
  1290.  
  1291.                 zmputs (_Attn);
  1292.                 continue;
  1293.  
  1294.             case ZDATA:
  1295.                 if (_rclhdr (_Rxhdr) != rxbytes)
  1296.                     {
  1297.                     if ( --n < 0)
  1298.                         {
  1299.                         return ERROR;
  1300.                         }
  1301.  
  1302.                     zmputs (_Attn);
  1303.                     continue;
  1304.                     }
  1305.  
  1306. moredata:
  1307.                 if (_Verbose > 1)
  1308.                     {
  1309.                     (*_do_report) (1, &rxbytes);
  1310.                     if (!sent_zm)
  1311.                         {
  1312.                         sent_zm = TRUE;
  1313.                         _say ("ZMODEM%s", _Crc32 ? " CRC-32" : "");
  1314.                         }
  1315.                         
  1316.                     }
  1317.                              
  1318.                 switch (c = _zrdata (secbuf, KSIZE))
  1319.                     {
  1320.                     case ZCAN:
  1321.                         _vfile ("rzfile: _zgethdr returned %d", c);
  1322.                         return ERROR;
  1323.  
  1324.                     case ERROR:            /* CRC error                         */
  1325.                         if (--n < 0)
  1326.                             {
  1327.                             _vfile ("rzfile: _zgethdr returned %d", c);
  1328.                             return ERROR;
  1329.                             }
  1330.                             
  1331.                         zmputs (_Attn);
  1332.                         continue;
  1333.  
  1334.                     case ZTIMEOUT:
  1335.                         if (--n < 0)
  1336.                             {
  1337.                             _vfile ("rzfile: _zgethdr returned %d", c);
  1338.                             return ERROR;
  1339.                             }
  1340.                             
  1341.                         continue;
  1342.  
  1343.                     case GOTCRCW:
  1344.                         n = 20;
  1345.                         putsec (secbuf, _Rxcount);
  1346.                         rxbytes += _Rxcount;
  1347.                         _stohdr (rxbytes);
  1348.                         _zshhdr (ZACK, _Txhdr);
  1349.                         _sendline (XON);
  1350.                         goto nxthdr;
  1351.                         
  1352.                     case GOTCRCQ:
  1353.                         n = 20;
  1354.                         putsec (secbuf, _Rxcount);
  1355.                         rxbytes += _Rxcount;
  1356.                         _stohdr (rxbytes);
  1357.                         _zshhdr (ZACK, _Txhdr);
  1358.                         goto moredata;
  1359.  
  1360.                     case GOTCRCG:
  1361.                         n = 20;
  1362.                         putsec (secbuf, _Rxcount);
  1363.                         rxbytes += _Rxcount;
  1364.                         goto moredata;
  1365.  
  1366.                     case GOTCRCE:
  1367.                         n = 20;
  1368.                         putsec (secbuf, _Rxcount);
  1369.                         rxbytes += _Rxcount;
  1370.                         goto nxthdr;
  1371.                     }    /* switch (c = _zrdata (secbuf, KSIZE)) */
  1372.                     
  1373.             }    /* switch (c = _zgethdr (_Rxhdr, 0)) */
  1374.  
  1375.         }    /* for (;;) */
  1376.         
  1377.     }    /* static int rzfile (void) */
  1378.  
  1379.  
  1380. /****************************************************************************
  1381. *    zmputs                                                                    *
  1382. *    Send a string to the modem, processing for \336 (sleep 1 sec) and \335     *
  1383. *    (break signal).                                                            *
  1384. ****************************************************************************/
  1385.  
  1386. static void zmputs (char *s)
  1387.     {
  1388.     int c;
  1389.  
  1390.     while (*s)
  1391.         {
  1392.         switch (c = *s++)
  1393.             {
  1394.             case '\336':
  1395.                 sleep (1);
  1396.                 continue;
  1397.                 
  1398.             case '\335':
  1399.                 _sendbrk ();
  1400.                 continue;
  1401.                 
  1402.             default:
  1403.                 _sendline (c);
  1404.             }    /* switch (c = *s++) */
  1405.             
  1406.         }    /* while (*s) */
  1407.         
  1408.     }    /* static void zmputs (char *s) */
  1409.  
  1410.  
  1411. /****************************************************************************
  1412. *    closeit                                                                    *
  1413. *    Close the receive dataset, return OK or ERROR.                            *
  1414. ****************************************************************************/
  1415.  
  1416. static int closeit (void)
  1417.     {
  1418.     if (close (fout) == -1)
  1419.         {
  1420.         _zperr_ ("file close ERROR\n");
  1421.         return ERROR;
  1422.         }
  1423.         
  1424. #if    0
  1425.     /* Bit fancy for MesS-DOS, what? */
  1426.     
  1427.     if (Modtime)
  1428.         {
  1429.         timep[0] = time (NULL);
  1430.         timep[1] = Modtime;
  1431.         utime (Pathname, timep);
  1432.         }
  1433.  
  1434.     if (Filemode)
  1435.         chmod (Pathname, (07777 & Filemode));
  1436. #endif
  1437.  
  1438.     return OK;
  1439.     }    /* static int closeit (void) */
  1440.  
  1441.  
  1442. /****************************************************************************
  1443. *    ackbibi                                                                    *
  1444. *    Ack a ZFIN packet, let bygones be bygones.                                *
  1445. ****************************************************************************/
  1446.  
  1447. static void ackbibi (void)
  1448.     {
  1449.     int n;
  1450.  
  1451.     _vfile ("ackbibi:");
  1452.     Readnum = 1;
  1453.     _stohdr (0L);
  1454.     for (n = 3; --n >= 0;)
  1455.         {
  1456.         purgeline ();
  1457.         _zshhdr (ZFIN, _Txhdr);
  1458.         switch (_readline (100))
  1459.             {
  1460.             case 'O':
  1461.                 _readline (1);            /* Discard 2nd 'O'                    */
  1462.                 _vfile ("ackbibi complete");
  1463.                 return;
  1464.  
  1465.             case RCDO:
  1466.                 return;
  1467.  
  1468.             case ZTIMEOUT:
  1469.             default:
  1470.                 break;
  1471.             }    /* switch (_readline (100)) */
  1472.             
  1473.         }    /* for (n = 3; --n >= 0;) */
  1474.         
  1475.     }    /* static void ackbibi (void) */
  1476.     
  1477.  
  1478. /****************************************************************************
  1479. *    sys2                                                                    *
  1480. *    Strip leading ! if present, do shell escape.                            *
  1481. ****************************************************************************/
  1482.  
  1483. static int sys2 (char *s)
  1484.     {
  1485.     if (*s == '!')
  1486.         ++s;
  1487.         
  1488.     return system (s);
  1489.     }    /* static int sys2 (char *s) */
  1490.     
  1491.  
  1492. /****************************************************************************
  1493. *    exec2                                                                    *
  1494. *    Strip leading '!' if present and do an exec.                            *
  1495. ****************************************************************************/
  1496.  
  1497. static void exec2 (char *s)
  1498.     {
  1499.     char *comspec;                        /* -> command.com                    */
  1500.     int result;                            /* result of exec                    */
  1501.     
  1502. #ifdef    DEBUGZ
  1503.     _vfile ("exec2: exec %s\n", s);
  1504. #endif
  1505.     if (*s == '!')
  1506.         ++s;
  1507.  
  1508.     if ((comspec = getenv ("COMSPEC")) != NULL)
  1509.         result = execl (comspec, "command", "/c", s, NULL);
  1510.     else
  1511.         result = execl ("command", "command", "/c", s, NULL);
  1512.  
  1513.     if (result == -1)
  1514.         perror ("exec2");
  1515.         
  1516.     }    /* static void exec2 (char *s) */
  1517. /* End of rz.c */
  1518.